// TradeRoute.cs
//
// Copyright (c) 2007 Mike Strobel
//
// This source code is subject to the terms of the Microsoft Reciprocal License (Ms-RL).
// For details, see <http://www.opensource.org/licenses/ms-rl.html>.
//
// All other rights reserved.

using System;
using System.ComponentModel;

using Supremacy.Game;
using Supremacy.Types;

namespace Supremacy.Universe
{
    /// <summary>
    /// Represents a trade route between two colonies.
    /// </summary>
    [Serializable]
    public class TradeRoute : Cloneable, INotifyPropertyChanged, ICloneable
    {
        private readonly int _sourceColonyId;
        private int _targetColonyId;
        private int _credits;

        /// <summary>
        /// Gets the <see cref="Colony"/> from which the <see cref="TradeRoute"/> originates.
        /// <value>The source colony.</value>
        /// </summary>
        public Colony SourceColony
        {
            get { return GameContext.Current.Universe.Objects[_sourceColonyId] as Colony; }
        }

        /// <summary>
        /// Gets or sets the <see cref="Colony"/> at which the <see cref="TradeRoute"/> terminates.
        /// </summary>
        /// <value>The target colony.</value>
        public Colony TargetColony
        {
            get { return GameContext.Current.Universe.Objects[_targetColonyId] as Colony; }
            set
            {
                _targetColonyId = (value != null) 
                    ? value.ObjectID 
                    : GameObjectID.InvalidID;
                foreach (TradeRoute route in SourceColony.TradeRoutes)
                {
                    if ((route != this) && route.IsAssigned
                        && (route.TargetColony == TargetColony))
                    {
                        route.TargetColony = null;
                    }
                }
                OnPropertyChanged("TargetColony");
                if (value == null)
                {
                    Credits = 0;
                }
                else
                {
                    Credits = (int)(0.015 * SourceColony.Population.CurrentValue
                        + 0.03 * TargetColony.Population.CurrentValue);
                }
            }
        }

        /// <summary>
        /// Gets a value indicating whether <see cref="TargetColony"/> is assigned.
        /// </summary>
        /// <value>
        /// <c>true</c> if <see cref="TargetColony"/> is assigned; otherwise, <c>false</c>.
        /// </value>
        public bool IsAssigned
        {
            get { return TargetColony != null; }
        }

        /// <summary>
        /// Gets or sets the credits generated by a <see cref="TradeRoute"/>.
        /// </summary>
        /// <value>The credits.</value>
        public int Credits
        {
            get { return _credits; }
            set
            {
                _credits = value;
                OnPropertyChanged("Credits");
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TradeRoute"/> class.
        /// </summary>
        /// <param name="sourceColony">
        /// The colony at which the <see cref="TradeRoute"/> originates.
        /// </param>
        public TradeRoute(Colony sourceColony)
        {
            if (sourceColony == null)
                throw new ArgumentNullException("sourceColony");
            _sourceColonyId = sourceColony.ObjectID;
            _targetColonyId = GameObjectID.InvalidID;
            _credits = 0;
        }


        /// <summary>
        /// Determines whether a <see cref="Colony"/> is a valid target for a <see cref="TradeRoute"/>.
        /// </summary>
        /// <param name="colony">The colony.</param>
        /// <returns>
        /// <c>true</c> if [is valid target colony] [the specified colony]; otherwise, <c>false</c>.
        /// </returns>
        public bool IsValidTargetColony(Colony colony)
        {
            if (colony == null)
                return true;
            if (!colony.IsOwned)
                return false;
            if (colony.OwnerID == SourceColony.OwnerID)
                return false;
            Supremacy.Diplomacy.Relationship relationship = GameContext.Current.Relationships[SourceColony.OwnerID, colony.OwnerID];
            if (relationship != null)
            {
                if (relationship.IsMember || relationship.OtherRelationship.IsMember)
                    return false;
                if (!relationship.IsEffectActive(Supremacy.Diplomacy.StipulationEffect.AllowTrade))
                    return false;
            }
            return true;
        }

        #region INotifyPropertyChanged Members
        /// <summary>
        /// Notifies clients that a property value has changed.
        /// </summary>
        [field: NonSerialized]
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Raises the <see cref="PropertyChanged"/> event.
        /// </summary>
        /// <param name="propertyName">Name of the property that has changed.</param>
        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion

        #region Implementation of ICloneable

        object ICloneable.Clone()
        {
            return this.Clone();
        }

        public TradeRoute Clone()
        {
            return Cloneable.Clone(this);
        }

        #endregion

        #region Implementation of ICloneable<TradeRoute>

        protected override Cloneable CreateInstance()
        {
            return new TradeRoute(this.SourceColony);
        }

        public override void  CloneFrom(Cloneable original)
        {
            var source = (TradeRoute)original;
            _targetColonyId = source._targetColonyId;
            _credits = source._credits;
        }

        #endregion
    }
}
